home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 3 / BBS in a box - Trilogy III.iso / Files / Tele / Pete Johnson / Tally 2.2<source> Folder / Tally.p < prev    next >
Encoding:
Text File  |  1991-06-29  |  25.4 KB  |  897 lines  |  [TEXT/PJMM]

  1. program Tally;
  2.  
  3. {     Written by Pete Johnson for the    Glassell Park BBS                        }
  4.  
  5. {    Version History                                                                    }
  6. {    --------------                                                                    }
  7. {    1.4    6/29/89                                                                    }
  8. {    1.5    11/19/89    Added WaitNextEvent in HelloTabby for MF            }
  9. {                            compatibility.                                            }
  10. {    2.0    2/3/90        Replaced LS Pascal file functions with Toolbox        }
  11. {                            calls.                                                        }
  12. {    2.1    5/23/90        Tally would not work if Tally Data file did not        }
  13. {                            exist -- fixed.                                            }
  14. {    2.2    6/28/91        Tally was getting stuck in an endless loop while    }
  15. {                            reading MSGHDR and could not cope with Config    }
  16. {                            file that was bigger than old SS size -- fixed.        }
  17. {                            Also added SIZE resource.                                }
  18.  
  19. {    This program counts messages in each section posted during the        }
  20. {    last 10 days.                                                                        }
  21.  
  22.     uses
  23.         Globals, HelloTabby;
  24.  
  25.     label
  26.         999;
  27.  
  28.     const
  29.         DAYSECS = 86400;        {    There are 86400 seconds in a 24-hour day            }
  30.         VERSION = '2.2';
  31.  
  32.     type
  33.         DateTimeRecord = packed array[1..6] of char;
  34.  
  35.         Header = record
  36.                 Status: packed array[1..2] of byte;    {    use Status[1] only    }
  37.                 MsgNo: longint;
  38.                 Section: packed array[1..2] of byte;    {    use Section[1] only    }
  39.                 TimeRcvd: DateTimeRecord;
  40.                 MsgFrom: string[31];
  41.                 MsgTo: string[31];
  42.                 MsgSubject: string[41];
  43.                 Destination: string[67];
  44.                 BeginText: longint;
  45.                 LengthText: longint;
  46.                 ReplyTo: longint;
  47.                 TimeSent: DateTimeRecord
  48.             end;
  49.  
  50.     var
  51.         ThisHeader: Header;
  52.         Echoes, PrivNet: packed array[1..255] of boolean;
  53.         SectionCount: array[1..255, 1..10] of integer;
  54.         StoredCount: array[1..255, 1..10] of longint;
  55.         SectionName: array[1..255] of string[25];
  56.         OmitSection: array[1..255] of boolean;
  57.         Done: boolean;
  58.         PathAndLogfile, PathAndIntro, PathAndStep, OmitFile, IntroLine, TallyData: STR255;
  59.         MsgPath, Ms, TempString, HiMsgStr: STR255;
  60.         SectionString, TheFileName, MESSAGESPath, TheExportFile: STR255;
  61.         Security, Modifier, Restriction, SectionType, ThisSection, ThisDay, DebugRef: integer;
  62.         ThisPub, ThisPriv, ThisStatus, HiBound, LoBound, Range, Increment, TheCursor: integer;
  63.         LowMsg, HiMsg, MSGTXTLength, NowSecs, ThenSecs, RcvdSecs, Adjust: longint;
  64.         DayMarker: array[1..10] of longint;
  65.         WhenRcvdString: DateTimeRecord;
  66.         TempTime, NowDateRec: DateTimeRec;
  67.         ResHandle2: Handle;
  68.         EchoFlag, HiMsgFlag, DeleteFlag: boolean;
  69.         DialogPointer: DialogPtr;
  70.         ACursorHandle: CursHandle;
  71.         ACursor: Cursor;
  72.  
  73.  
  74. {-----------------------------------------------------------------                            }
  75. { FrameDItem draws a round cornered rectangle around the item rectangle of a given item     }
  76. { in a given dialog. This is usually done to indicate the default choice button of a dialog.            }
  77. {-----------------------------------------------------------------                            }
  78.  
  79.     procedure FrameDItem (dLog: DialogPtr; iNum: integer);
  80.  
  81.         var
  82.             iBox: Rect;
  83.             iType: integer;
  84.             iHandle: Handle;
  85.             oldPenState: PenState;
  86.  
  87.     begin
  88.         GetPenState(oldPenState);
  89.         GetDItem(dLog, iNum, iType, iHandle, iBox);
  90.         InsetRect(iBox, -4, -4);
  91.         PenSize(3, 3);
  92.         FrameRoundRect(iBox, 16, 16);
  93.         SetPenState(oldPenState)
  94.     end;
  95.  
  96. { ------------------------------------------------------ }
  97.  
  98.     function AtEOF (fRefNum: Integer): Boolean;
  99.         var
  100.             currPos, eofPos: LongInt;
  101.  
  102.     begin
  103.         Err := GetFPos(fRefNum, currPos);
  104.         Err := GetEOF(fRefNum, eofPos);
  105.         AtEOF := currPos = eofPos
  106.     end;
  107.  
  108. { ------------------------------------------------------ }
  109.  
  110.     function Wr (FileRefNum: integer; TheMessage: string): OSErr;
  111.  
  112. {    Writes string (without length byte) to text file, returns error code    }
  113.  
  114.         var
  115.             TheLength: longint;
  116.  
  117.     begin
  118.         TheLength := length(TheMessage);
  119.         Wr := FSWrite(FileRefNum, TheLength, Pointer(ord(@TheMessage) + 1));
  120.     end;
  121.  
  122. {-----------------------------------------------------------------    }
  123.  
  124.     function WrLn (FileRefNum: integer; TheMessage: string): OSErr;
  125.  
  126. {    Writes string (without length byte) to text file, returns error code    }
  127.  
  128.     begin
  129.         TheMessage := concat(TheMessage, ENDLINE);
  130.         WrLn := Wr(FileRefNum, TheMessage);
  131.     end;
  132.  
  133. {-----------------------------------------------------------------    }
  134.  
  135.     function ReadLine (FileRefNum: integer; var TheMessage: string): OSErr;
  136.  
  137.         var
  138.             myPB: ParamBlockRec;
  139.             myString: STR255;
  140.  
  141.     begin
  142.         myString := '';
  143.         myPB.ioCompletion := nil;
  144.         myPB.ioRefNum := FileRefNum;
  145.         myPB.ioBuffer := Pointer(@TheMessage[1]);
  146.         myPB.ioReqCount := 255;
  147.         myPB.ioPosMode := 3456; {ASCII 13*256+128}
  148.         myPB.ioPosOffset := 0; {ignored}
  149.         ReadLine := PBRead(@myPB, False);
  150.         TheMessage[0] := Char(myPB.ioActCount - 1); {Drop CR}
  151.     end;
  152.  
  153. {-----------------------------------------------------------------    }
  154.  
  155.     procedure SkipBlanks (fRef: integer);
  156.  
  157. {    Skips blanks until eof or a nonblank is found    }
  158.  
  159.         var
  160.             currPos, HowMuch: longint;
  161.             TheChar: char;
  162.  
  163.     begin
  164.         TheChar := space;
  165.         HowMuch := 1;
  166.         while ((TheChar = SPACE) | (TheChar = TAB) | (TheChar = ENDLINE)) & (not AtEOF(fRef)) do
  167.             begin
  168.                 Err := FSRead(fRef, HowMuch, @TheChar);
  169.             end;
  170.         Err := GetFPos(fRef, currPos);
  171.         if currPos > 0 then
  172.             Err := SetFPos(fRef, fsAtMark, -1);
  173.     end;
  174.  
  175. {-----------------------------------------------------------------    }
  176.  
  177.     function ReadData (fRef: integer): longint;
  178.  
  179. {    Skips blanks until eof or a nonblank is found, then reads until eof or a blank is found     and converts to integer}
  180.  
  181.         var
  182.             currPos, HowMuch, TempLong: longint;
  183.             TheChar: char;
  184.             TempString: str255;
  185.  
  186.     begin
  187.         TempString := '';
  188.         TheChar := space;
  189.         HowMuch := 1;
  190.         while ((TheChar = SPACE) | (TheChar = TAB) | (TheChar = ENDLINE)) & (not AtEOF(fRef)) & (Err = NoErr) do
  191.             begin
  192.                 Err := FSRead(fRef, HowMuch, @TheChar);
  193.             end;
  194.         if (not AtEOF(fRef)) then
  195.             begin
  196.                 Err := GetFPos(fRef, currPos);
  197.                 if currPos > 0 then
  198.                     Err := SetFPos(fRef, fsAtMark, -1);
  199.                 while ((TheChar <> SPACE) | (TheChar <> TAB) | (TheChar <> ENDLINE)) & (not AtEOF(fRef)) & (Err = NoErr) do
  200.                     begin
  201.                         Err := FSRead(fRef, HowMuch, @TheChar);
  202.                         TempString := concat(TempString, TheChar)
  203.                     end;
  204.                 StringToNum(TempString, TempLong);
  205.                 ReadData := TempLong;
  206.             end        {    if (not AtEOF(fRef))        }
  207.         else
  208.             ReadData := 0;
  209.     end;
  210.  
  211. {-----------------------------------------------------------------    }
  212.  
  213.     procedure RotateCursorBall;
  214.  
  215.     begin
  216.         Increment := 1;
  217.         ACursorHandle := GetCursor(TheCursor);
  218.         SetCursor(ACursorHandle^^);
  219.         if TheCursor > 130 then
  220.             TheCursor := 128
  221.         else
  222.             TheCursor := TheCursor + 1;
  223.     end;
  224.  
  225. {-----------------------------------------------------------------    }
  226.  
  227.     function MakeTime (Index: integer; Separator: char): string;
  228.  
  229. { Function changes three chars of DateTimeRecord to formatted time or date string    }
  230.  
  231.         var
  232.             MakeTimeString, LocalTemp: STR255;
  233.  
  234.     begin
  235.         LocalTemp := '';
  236.         NumToString(ord(WhenRcvdString[Index + 1]), LocalTemp);
  237.         if length(LocalTemp) = 1 then
  238.             LocalTemp := concat('0', LocalTemp);
  239.         MakeTimeString := concat(LocalTemp, Separator);
  240.         NumToString(ord(WhenRcvdString[Index + 2]), LocalTemp);
  241.         if length(LocalTemp) = 1 then
  242.             LocalTemp := concat('0', LocalTemp);
  243.         MakeTimeString := concat(MakeTimeString, LocalTemp, Separator);
  244.         NumToString(ord(WhenRcvdString[Index + 3]), LocalTemp);
  245.         if length(LocalTemp) = 1 then
  246.             LocalTemp := concat('0', LocalTemp);
  247.         MakeTime := concat(MakeTimeString, LocalTemp)
  248.     end;
  249.  
  250. { ------------------------------------------------------ }
  251.  
  252.     function Make2Digits (ConvertFrom: string): integer;
  253.  
  254. {    Converts two-character string into an ascii value        }
  255.  
  256.         var
  257.             Num1, Num2: integer;
  258.  
  259.     begin
  260.         Num1 := ord(ConvertFrom[1]) - ord('0');
  261.         Num2 := ord(ConvertFrom[2]) - ord('0');
  262.         Make2Digits := Num2 + (Num1 * 10)
  263.     end;
  264.  
  265. { ------------------------------------------------------ }
  266.  
  267.     procedure ReadConfig;
  268.  
  269.         var
  270.             ConfigRefNum: integer;
  271.             CharsToSend: longint;
  272.             AString: str255;
  273.  
  274.     begin
  275.         AString := '';
  276.         MESSAGESPath := '';
  277.         Err := FSOpen(concat(gDefaultPath, 'Config'), vRefNum, ConfigRefNum);
  278.         if Err = noErr then
  279.             begin
  280.                 CharsToSend := 80;
  281.                 if Err = noErr then
  282.                     Err := SetFPos(ConfigRefNum, fsFromStart, 139);
  283.                 if Err = noErr then
  284.                     Err := FSRead(ConfigRefNum, CharsToSend, @AString);
  285.                 if length(AString) > 0 then
  286.                     MESSAGESPath := AString;
  287.                 MESSAGESPath := concat(MESSAGESPath, ':MESSAGES');
  288.                 if Err = noErr then
  289.                     Err := FSClose(ConfigRefNum)
  290.             end;
  291.         if Err <> NoErr then
  292.             goto 999;
  293.     end;
  294.  
  295. { ------------------------------------------------------ }
  296.  
  297.     procedure ReadMESSAGES;
  298.  
  299. { Procedure reads the MESSAGES file                                }
  300.  
  301.         type
  302.             AString = string;
  303.             AStringPtr = ^AString;
  304.             AStringHdl = ^AStringPtr;
  305.             ALongint = Longint;
  306.             ALongintPtr = ^ALongint;
  307.             ALongintHdl = ^ALongintPtr;
  308.  
  309.         var
  310.             MSCount, MSGRefNum: integer;
  311.             MSChar, OneChar: char;
  312.             MsgStringHandle: AStringHdl;
  313.             MsgLongintHandle: ALongintHdl;
  314.             CharsToSend: longint;
  315.  
  316.     begin
  317.         MsgPath := '';
  318.         MsgStringHandle := AStringHdl(NewHandle(sizeOf(AString)));
  319.         MsgLongintHandle := ALongintHdl(NewHandle(sizeOf(ALongint)));
  320.         CharsToSend := 255;
  321.         Err := FSOpen(MESSAGESPath, vRefNum, MSGRefNum);
  322.         Err := FSRead(MSGRefNum, CharsToSend, Ptr(MsgStringHandle^));
  323.         MsgPath := concat(MsgStringHandle^^, ':');
  324.  
  325.         CharsToSend := 4;
  326.         Err := SetFPos(MSGRefNum, fsFromStart, 50);
  327.         Err := FSRead(MSGRefNum, CharsToSend, Ptr(MsgLongintHandle^));
  328.         LowMsg := MsgLongintHandle^^;
  329.         Err := FSRead(MSGRefNum, CharsToSend, Ptr(MsgLongintHandle^));
  330.         HiMsg := MsgLongintHandle^^;
  331.  
  332.         for MSCount := 1 to 255 do
  333.             begin
  334.                 Err := SetFPos(MSGRefNum, fsFromStart, (62 + (MSCount - 1) * 36));
  335.                 CharsToSend := 255;
  336.                 Err := FSRead(MSGRefNum, CharsToSend, Ptr(MsgStringHandle^));
  337.                 SectionName[MSCount] := MsgStringHandle^^;
  338.  
  339.             end;        {    for MSCount := 1 to 255 do    }
  340.  
  341.         DisposHandle(Handle(MsgStringHandle));
  342.         DisposHandle(Handle(MsgLongintHandle));
  343.         Err := FSClose(MSGRefNum);
  344.     end;
  345.  
  346. { ------------------------------------------------------ }
  347.  
  348.     procedure MakeTextFile (FileName: string);
  349.  
  350. { Sets up QUED-compatible text  file                                }
  351.  
  352.         var
  353.             fndrInfo: FInfo;
  354.  
  355.     begin
  356.         Err := GetFInfo(FileName, vRefNum, fndrInfo);
  357.         if Err = noErr then
  358.             begin
  359.                 fndrInfo.fdType := 'TEXT';
  360.                 fndrInfo.fdCreator := 'QED1';
  361.                 Err := SetFInfo(FileName, vRefNum, fndrInfo);
  362.             end
  363.         else
  364.             Err := Create(FileName, vRefNum, 'QED1', 'TEXT');
  365.     end;
  366.  
  367. { ------------------------------------------------------ }
  368.  
  369.     procedure MakeSeconds (Convert: DateTimeRecord);
  370.  
  371.         var
  372.             Temp: DateTimeRec;
  373.  
  374.     begin
  375.         with Temp do
  376.             begin
  377.                 Month := ord(Convert[1]);
  378.                 Day := ord(Convert[2]);
  379.                 Year := ord(Convert[3]) + 1900;
  380.                 Hour := 0;
  381.                 Minute := 0;
  382.                 Second := 0;
  383.             end;
  384.         Date2Secs(Temp, RcvdSecs);
  385.  
  386.     end;
  387.  
  388. { ------------------------------------------------------ }
  389.     function theFilePos (FRef: integer): longint;
  390.  
  391.         var
  392.             CurrentLoc: longint;
  393.  
  394.     begin
  395.         Err := GetFPos(FRef, CurrentLoc);
  396.         theFilePos := CurrentLoc;
  397.     end;
  398. { ------------------------------------------------------ }
  399.  
  400.     procedure ProcessMSGHDR;
  401.  
  402. { Processes MSGHDR file                                }
  403.  
  404.         const
  405.             HeaderSize = SizeOf(Header);
  406.  
  407.         var
  408.             Count1, Count2, DayCount, MsgHdrRef: integer;
  409.             LastMsgNo, HowMuch: longint;
  410.  
  411.     begin
  412.         for Count1 := 1 to 255 do
  413.             for Count2 := 1 to 10 do
  414.                 SectionCount[Count1, Count2] := 0;
  415.         for DayCount := 1 to 10 do
  416.             DayMarker[DayCount] := HiMsg;
  417.         ThenSecs := NowSecs - (10 * DAYSECS);
  418.         Secs2Date(ThenSecs, TempTime);            {    Get the date 10 days ago                                        }
  419.         with TempTime do                                {    Set the time to the start of that day                            }
  420.             begin
  421.                 Hour := 0;
  422.                 Minute := 0;
  423.                 Second := 0;
  424.             end;
  425.         Date2Secs(TempTime, ThenSecs);            {    We now have the lower bound for qualifying messages    }
  426.         Done := false;
  427.         TheFileName := concat(MsgPath, 'MSGHDR');
  428.         Err := FSOpen(TheFileName, vRefNum, MsgHdrRef);
  429.         Err := SetFPos(MsgHdrRef, fsFromLEOF, 0);
  430.         DayCount := 1;
  431.         LastMsgNo := HiMsg;
  432.         Increment := 5;
  433.         while (theFilePos(MsgHdrRef) >= HeaderSize) & (not Done) & (Err = NoErr) do
  434.             begin
  435.                 if Increment > 4 then
  436.                     RotateCursorBall
  437.                 else
  438.                     Increment := succ(Increment);
  439.                 HowMuch := HeaderSize;
  440.                 if (theFilePos(MsgHdrRef) >= HowMuch) then
  441.                     Err := SetFPos(MsgHdrRef, fsFromStart, theFilePos(MsgHdrRef) - HowMuch);
  442.                 Err := FSRead(MsgHdrRef, HowMuch, @ThisHeader);
  443.                 with ThisHeader do
  444.                     begin
  445.                         ThisStatus := Status[1];                {    use 'good' byte                }
  446.                         ThisSection := Section[1];                {    use 'good' byte                }
  447.                         MakeSeconds(TimeRcvd);                {    returns RcvdSecs            }
  448.                         if (BitAnd(1, ThisStatus) = 0) then                            {    Not deleted                                    }
  449.                             if (ThisSection > 0) & (ThisSection < 256) then            {    Make sure it's a valid section number    }
  450.                                 if SectionName[ThisSection] <> '' then                    {    Make sure it's a defined section             }
  451.                                     if (RcvdSecs > ThenSecs) then
  452.                                         begin
  453.                                             ThisDay := 11 - ((RcvdSecs - ThenSecs) div 86400);
  454.                                             while DayCount < ThisDay do
  455.                                                 begin
  456.                                                     DayMarker[DayCount] := LastMsgNo;
  457.                                                     DayCount := DayCount + 1;
  458.                                                 end;
  459.                                             LastMsgNo := MsgNo;
  460.                                             SectionCount[ThisSection, ThisDay] := SectionCount[ThisSection, ThisDay] + 1
  461.                                         end        {    if (RcvdSecs > ThenSecs)    }
  462.                                     else
  463.                                         begin
  464.                                             Done := true;
  465.                                             DayMarker[10] := LastMsgNo;
  466.                                         end;
  467.                     end;                    {    with ThisHeader                    }
  468.                 Err := SetFPos(MsgHdrRef, fsFromStart, theFilePos(MsgHdrRef) - HowMuch);
  469.             end;                        {    while (filepos(MSGHDR) > 0)    }
  470.         Err := FSClose(MsgHdrRef);
  471.     end;                            {    procedure                            }
  472.  
  473. { ------------------------------------------------------ }
  474.  
  475.     procedure WriteReport;
  476.  
  477. { Procedure writes report with message counts    }
  478.  
  479.         var
  480.             Count1, Count2, TheTotal, MLogRef, IntroRef, StepRef: integer;
  481.             DayTotals: array[1..10] of integer;
  482.             AM: boolean;
  483.             DateStamp, TempDate: str255;
  484.  
  485.     begin
  486.         for Count1 := 1 to 10 do
  487.             DayTotals[Count1] := 0;
  488.         Err := FSDelete(PathAndLogfile, vRefNum);
  489.         MakeTextFile(PathAndLogfile);
  490.         Err := FSOpen(PathAndLogfile, vRefNum, MLogRef);
  491.         Err := WrLn(MLogRef, '');
  492.         Err := WrLn(MLogRef, '                            Message Activity Report ');
  493.         Err := Wr(MLogRef, '                         Prepared ');
  494.         with NowDateRec do
  495.             begin
  496.  
  497.                 if month < 10 then
  498.                     DateStamp := stringof(month : 1)
  499.                 else
  500.                     DateStamp := stringof(month : 2);
  501.  
  502.                 DateStamp := concat(DateStamp, '/');
  503.  
  504.                 if day < 10 then
  505.                     TempDate := stringof(day : 1)
  506.                 else
  507.                     TempDate := stringof(day : 2);
  508.  
  509.                 DateStamp := concat(DateStamp, TempDate, '/', stringof((year - 1900) : 2), ' at ');
  510.  
  511.                 if hour >= 12 then
  512.                     begin
  513.                         AM := false;
  514.                         if hour > 12 then
  515.                             hour := hour - 12;
  516.                     end
  517.                 else
  518.                     AM := true;
  519.                 if hour < 10 then
  520.                     TempDate := stringof(hour : 1)
  521.                 else
  522.                     TempDate := stringof(hour : 2);
  523.  
  524.                 DateStamp := concat(DateStamp, TempDate, ':');
  525.  
  526.                 if minute < 10 then
  527.                     TempDate := concat('0', stringof(hour : 1))
  528.                 else
  529.                     TempDate := stringof(minute : 2);
  530.  
  531.                 DateStamp := concat(DateStamp, TempDate);
  532.  
  533.                 if AM then
  534.                     DateStamp := concat(DateStamp, ' a.m.')
  535.                 else
  536.                     DateStamp := concat(DateStamp, ' p.m.');
  537.  
  538.                 Err := WrLn(MLogRef, DateStamp);
  539.  
  540.             end;        {    with NowDateRec do    }
  541.  
  542.         Err := WrLn(MLogRef, '');
  543.  
  544.         if PathAndIntro <> '' then
  545.             begin
  546.                 Err := FSOpen(PathAndIntro, vRefNum, IntroRef);
  547.                 if Err = NoErr then
  548.                     while not AtEOF(IntroRef) do
  549.                         begin
  550.                             Err := ReadLine(IntroRef, IntroLine);
  551.                             Err := WrLn(MLogRef, IntroLine)
  552.                         end;
  553.                 Err := FSClose(IntroRef);
  554.                 Err := WrLn(MLogRef, '')
  555.             end;
  556.  
  557.         Err := WrLn(MLogRef, 'Message             ---------------------- Days Ago ------------------ ');
  558.         Err := WrLn(MLogRef, 'Section             Today    1    2    3    4    5    6    7    8    9    Avg');
  559.         Err := WrLn(MLogRef, '-----------------------------------------------------------------------------');
  560.         for Count1 := 1 to 255 do
  561.             begin
  562.                 if Increment > 4 then
  563.                     RotateCursorBall
  564.                 else
  565.                     Increment := Increment + 1;
  566.                 if (SectionName[Count1] <> '') and not OmitSection[Count1] then
  567.                     begin
  568.                         SectionName[Count1] := concat(SectionName[Count1], '                    ');        {    Pad section name with 20 blanks        }
  569.                         Err := Wr(MLogRef, copy(SectionName[Count1], 1, 20));                            {     Keep section names < 21 characters    }
  570.                         TheTotal := 0;
  571.                         for Count2 := 1 to 10 do
  572.                             begin
  573.                                 if ((Count2 - Adjust) > 0) then        {    Don't do this unless we're within bounds    }
  574.                                     if SectionCount[Count1, Count2] < StoredCount[Count1, Count2 - Adjust] then
  575.                                         SectionCount[Count1, Count2] := StoredCount[Count1, Count2 - Adjust];
  576.                                 DayTotals[Count2] := DayTotals[Count2] + SectionCount[Count1, Count2];
  577.                                 TheTotal := TheTotal + SectionCount[Count1, Count2];
  578.                                 Err := Wr(MLogRef, stringof(SectionCount[Count1, Count2] : 5));
  579.                             end;        {    Count2 := 1 to 10    }
  580.                         if (TheTotal mod 10) > 4 then
  581.                             TheTotal := TheTotal + 5;
  582.                         Err := Wr(MLogRef, stringof((TheTotal div 10) : 7));
  583.                         Err := WrLn(MLogRef, '');
  584.                     end;        {    SectionName[Count1] <> ''    }
  585.             end;        {    Count1 := 1 to 255    }
  586.         TheTotal := 0;
  587.         Err := WrLn(MLogRef, '');
  588.         Err := Wr(MLogRef, 'Daily Totals        ');
  589.         for Count1 := 1 to 10 do
  590.             begin
  591.                 Err := Wr(MLogRef, stringof(DayTotals[Count1] : 5));
  592.                 TheTotal := TheTotal + DayTotals[Count1];
  593.             end;
  594.         if (TheTotal mod 10) > 4 then
  595.             TheTotal := TheTotal + 5;
  596.         Err := Wr(MLogRef, stringof((TheTotal div 10) : 7));
  597.         Err := WrLn(MLogRef, '');
  598.         Err := FSClose(MLogRef);
  599.  
  600.         Err := FSDelete(PathAndStep, vRefNum);
  601.         MakeTextFile(PathAndStep);
  602.         Err := FSOpen(PathAndStep, vRefNum, StepRef);
  603.         Err := WrLn(StepRef, '');
  604.         Err := WrLn(StepRef, '     Message Numbers By Days Ago');
  605.         Err := WrLn(StepRef, '');
  606.         Err := WrLn(StepRef, 'Use this table to read messages you might');
  607.         Err := WrLn(StepRef, 'have missed. To see all messages posted in');
  608.         Err := WrLn(StepRef, 'the last two days, just read forward from');
  609.         Err := WrLn(StepRef, 'the second message number in this list.');
  610.         Err := WrLn(StepRef, '');
  611.         Err := WrLn(StepRef, '             Day / Msg No');
  612.         Err := WrLn(StepRef, '             ------------');
  613.         for Count1 := 1 to 10 do
  614.             Err := WrLn(StepRef, concat('             ', stringof(Count1 : 2), ' --', stringof(DayMarker[Count1] : 7)));
  615.         Err := FSClose(StepRef)
  616.     end;
  617.  
  618. { ------------------------------------------------------ }
  619.  
  620.     procedure HandleDialog;
  621.  
  622.         var
  623.             theDialog: DialogPtr;
  624.             ItemHit, itemType, whichItem: integer;
  625.             itemHandle: Handle;
  626.             dispRect: Rect;
  627.             thisButton: ControlHandle;
  628.  
  629.         const
  630.             disableItem = 128;
  631.  
  632.     begin
  633.         paramText(VERSION, '', '', '');
  634.         InitCursor;
  635.         theDialog := GetNewDialog(1002, nil, POINTER(-1));                {IM I-413}
  636.         SetPort(theDialog);
  637.         FrameDItem(theDialog, OK);
  638.         DrawDialog(theDialog);
  639.  
  640.         NextLaunch := GetString(500)^^;
  641.  
  642.         getDItem(theDialog, 3, itemType, itemHandle, dispRect);
  643.         SetIText(Handle(itemHandle), NextLaunch);
  644.  
  645.         getDItem(theDialog, 4, itemType, itemHandle, dispRect);
  646.         SetIText(Handle(itemHandle), PathAndLogfile);
  647.  
  648.         getDItem(theDialog, 5, itemType, itemHandle, dispRect);
  649.         SetIText(Handle(itemHandle), PathAndIntro);
  650.  
  651.         getDItem(theDialog, 6, itemType, itemHandle, dispRect);
  652.         SetIText(Handle(itemHandle), PathAndStep);
  653.  
  654.         getDItem(theDialog, 7, itemType, itemHandle, dispRect);
  655.         SetIText(Handle(itemHandle), OmitFile);
  656.  
  657.         getDItem(theDialog, 8, itemType, itemHandle, dispRect);
  658.         SetIText(Handle(itemHandle), TallyData);
  659.  
  660.         if StillDown then
  661.             repeat
  662.             until not Button;
  663.         repeat
  664.             ModalDialog(nil, ItemHit);                                            {IM I-415}
  665.  
  666.             case ItemHit of
  667.                 1: { OK button hit -- save resources }
  668.                     begin
  669.                         getDItem(theDialog, 3, itemType, itemHandle, dispRect);
  670.                         GetIText(Handle(itemHandle), NextLaunch);
  671.                         ResHandle2 := GetResource('STR ', 500);
  672.                         RmveResource(ResHandle2);
  673.                         UpdateResFile(CurrentResFile);
  674.                         AddResource(Handle(NewString(NextLaunch)), 'STR ', 500, 'Next Launch');
  675.  
  676.                         getDItem(theDialog, 4, itemType, itemHandle, dispRect);
  677.                         GetIText(Handle(itemHandle), PathAndLogfile);
  678.                         ResHandle2 := GetResource('STR ', 501);
  679.                         RmveResource(ResHandle2);
  680.                         UpdateResFile(CurrentResFile);
  681.                         AddResource(Handle(NewString(PathAndLogfile)), 'STR ', 501, 'Path:Logfile');
  682.  
  683.                         getDItem(theDialog, 5, itemType, itemHandle, dispRect);
  684.                         GetIText(Handle(itemHandle), PathAndIntro);
  685.                         ResHandle2 := GetResource('STR ', 502);
  686.                         RmveResource(ResHandle2);
  687.                         UpdateResFile(CurrentResFile);
  688.                         AddResource(Handle(NewString(PathAndIntro)), 'STR ', 502, 'Path:Intro');
  689.  
  690.                         getDItem(theDialog, 6, itemType, itemHandle, dispRect);
  691.                         GetIText(Handle(itemHandle), PathAndStep);
  692.                         ResHandle2 := GetResource('STR ', 503);
  693.                         RmveResource(ResHandle2);
  694.                         UpdateResFile(CurrentResFile);
  695.                         AddResource(Handle(NewString(PathAndStep)), 'STR ', 503, 'Path:Stepfile');
  696.  
  697.                         getDItem(theDialog, 7, itemType, itemHandle, dispRect);
  698.                         GetIText(Handle(itemHandle), OmitFile);
  699.                         ResHandle2 := GetResource('STR ', 504);
  700.                         RmveResource(ResHandle2);
  701.                         UpdateResFile(CurrentResFile);
  702.                         AddResource(Handle(NewString(OmitFile)), 'STR ', 504, 'Path:Omitfile');
  703.  
  704.                         getDItem(theDialog, 8, itemType, itemHandle, dispRect);
  705.                         GetIText(Handle(itemHandle), TallyData);
  706.                         ResHandle2 := GetResource('STR ', 505);
  707.                         RmveResource(ResHandle2);
  708.                         UpdateResFile(CurrentResFile);
  709.                         AddResource(Handle(NewString(TallyData)), 'STR ', 505, 'Path:Datafile');
  710.  
  711.                     end;        {    case ItemHit of 1    }
  712.  
  713.                 2: 
  714.                     ; { Cancel button hit—do nothing    }
  715.  
  716.                 otherwise
  717.                     ;    {    do nothing    }
  718.  
  719.             end;
  720.         until (ItemHit = 1) or (ItemHit = 2);
  721.         DisposDialog(theDialog)
  722.     end;
  723.  
  724. { ------------------------------------------------------ }
  725.  
  726.     procedure GetStoredData;
  727.  
  728.         var
  729.             Section, Day, DataRef: integer;
  730.             WhenStored: DateTimeRec;
  731.             StoredSecs, TempSecs, LastSession, logicalEOF: longint;
  732.             Temp: char;
  733.             TempString: str255;
  734.  
  735.     begin
  736.         LastSession := 0;
  737.         for Section := 1 to 255 do
  738.             for Day := 1 to 10 do
  739.                 StoredCount[Section, Day] := 0;
  740.  
  741.         Err := FSOpen(TallyData, vRefNum, DataRef);
  742.         if Err = NoErr then
  743.             Err := GetEOF(DataRef, logicalEOF);
  744.         TheCursor := 128;
  745.         Increment := 9;
  746.         InitCursor;
  747.         Section := 1;
  748.         if (logicalEOF > 0) & (Err = NoErr) then
  749.             begin
  750.                 SkipBlanks(DataRef);
  751.                 Err := ReadLine(DataRef, TempString);
  752.                 StringToNum(TempString, LastSession);
  753.                 SkipBlanks(DataRef);
  754.                 while (not AtEOF(DataRef)) & (Section < 256) & (Err = NoErr) do
  755.                     begin
  756.                         if Increment > 8 then
  757.                             RotateCursorBall
  758.                         else
  759.                             Increment := Increment + 1;
  760.                         Section := ReadData(DataRef);
  761.                         if (Section > 0) and (Section < 256) then
  762.                             for Day := 1 to 10 do
  763.                                 StoredCount[Section, Day] := ReadData(DataRef);
  764.                     end;        {    while (not AtEOF(DataRef)) and (Section < 256)    }
  765.                 Err := FSClose(DataRef);
  766.             end;
  767.         if LastSession <> 0 then
  768.             begin
  769.                 Secs2Date(LastSession, TempTime);            {    Get the time at 00:00:00    }
  770.                 with TempTime do
  771.                     begin
  772.                         Hour := 0;
  773.                         Minute := 0;
  774.                         Second := 0;
  775.                     end;        {    with TempTime    }
  776.                 Date2Secs(TempTime, LastSession);            {    We now have the very beginning of the day    }
  777.  
  778.                 Secs2Date(NowSecs, TempTime);                    {    Get the time at 00:00:00    }
  779.                 with TempTime do
  780.                     begin
  781.                         Hour := 0;
  782.                         Minute := 0;
  783.                         Second := 0;
  784.                     end;
  785.                 Date2Secs(TempTime, TempSecs);                {    We now have the very beginning of the day    }
  786.  
  787.                 Adjust := (TempSecs - LastSession) div DAYSECS;
  788.  
  789.             end        {    if LastSession <> 0    }
  790.         else
  791.             Adjust := 0;
  792.     end;
  793.  
  794. { ------------------------------------------------------ }
  795.  
  796.     procedure StoreCounts;
  797.  
  798.         var
  799.             Section, Day, DataRef: integer;
  800.  
  801.     begin
  802.         Err := FSDelete(TallyData, vRefNum);
  803.         MakeTextFile(TallyData);
  804.         Err := FSOpen(TallyData, vRefNum, DataRef);
  805.         Err := WrLn(DataRef, stringof(NowSecs : 1));
  806.         for Section := 1 to 255 do
  807.             begin
  808.                 if Increment > 2 then
  809.                     RotateCursorBall
  810.                 else
  811.                     Increment := Increment + 1;
  812.                 if (SectionName[Section] <> '') and (not OmitSection[Section]) then
  813.                     begin
  814.                         Err := Wr(DataRef, concat(stringof(Section : 1), chr(9)));
  815.                         for Day := 1 to 10 do
  816.                             if Day < 10 then
  817.                                 Err := Wr(DataRef, concat(stringof(SectionCount[Section, Day] : 1), chr(9)))
  818.                             else
  819.                                 Err := WrLn(DataRef, stringof(SectionCount[Section, Day] : 1));
  820.                     end;
  821.             end;
  822.         Err := FSClose(DataRef)
  823.     end;
  824.  
  825. { ------------------------------------------------------ }
  826.  
  827.     procedure ReadOmits;
  828.  
  829.         var
  830.             OmitRefNum, OmitCount: integer;
  831.             logicalEOF, currPos: longint;
  832.             OmitLine: STR255;
  833.             SectNo: longint;
  834.  
  835.     begin
  836.         for OmitCount := 1 to 255 do
  837.             OmitSection[OmitCount] := false;
  838.         if OmitFile <> '' then
  839.             begin
  840.                 Err := FSOpen(OmitFile, vRefNum, OmitRefNum);
  841.                 if Err = noErr then
  842.                     Err := GetEOF(OmitRefNum, logicalEOF);
  843.                 if (Err = noErr) then
  844.                     begin
  845.                         Err := GetFPos(OmitRefNum, currPos);
  846.                         while (currPos < logicalEOF) do
  847.                             begin
  848.                                 Err := ReadLine(OmitRefNum, OmitLine);
  849.                                 StringToNum(OmitLine, SectNo);
  850.                                 if (SectNo > 0) and (SectNo < 256) then
  851.                                     OmitSection[SectNo] := true;
  852.                                 Err := GetFPos(OmitRefNum, currPos)
  853.                             end;        {    while (currPos < logicalEOF)        }
  854.                         Err := FSClose(OmitRefNum)
  855.                     end        {    if (Err = noErr)        }
  856.             end        {    if OmitFile <> ''        }
  857.     end;
  858.  
  859. { ------------------------------------------------------ }
  860.  
  861. begin
  862.     CurrentResFile := CurResFile;
  863.     PathAndLogfile := GetString(501)^^;
  864.     PathAndIntro := GetString(502)^^;
  865.     PathAndStep := GetString(503)^^;
  866.     OmitFile := GetString(504)^^;
  867.     TallyData := GetString(505)^^;
  868.     if Button then
  869.         HandleDialog        { If user is holding down the mouse button, reconfigure and end            }
  870.     else
  871.         begin
  872.             HelloTabby;    { find out what's next on the launchpad }
  873.             DialogPointer := GetNewDialog(1001, nil, POINTER(-1));
  874.             paramText(VERSION, '', '', '');
  875.             SetPort(DialogPointer);
  876.             forecolor(RedColor);
  877.             TextSize(9);
  878.             TextFont(Geneva);
  879.             DrawDialog(DialogPointer);
  880.             ReadConfig;
  881.             ReadMESSAGES;
  882.             GetDateTime(NowSecs);                        {    How many seconds now?    }
  883.             Secs2Date(NowSecs, NowDateRec);
  884.             GetStoredData;
  885.             ReadOmits;
  886.             ProcessMSGHDR;
  887.             WriteReport;
  888.             StoreCounts;
  889.  
  890. 999:
  891.             DisposDialog(DialogPointer);
  892.  
  893.             SetCursor(Arrow);
  894.             if NextLaunch <> '' then
  895.                 LaunchNextAppl
  896.         end    {    if  not Button        }
  897. end.